using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using WcfService1.DTO;
using Omu.ValueInjecter;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" Jurnal to change the class name "JurnalServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class JurnalServices : IJurnalServices
    {
        private readonly JurnalRepository jurnalRepository;
        private readonly WcfSessionStorage _session;
        private readonly CoaRepository coaRepository;

        public JurnalServices()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            _session = new WcfSessionStorage();
            jurnalRepository = new JurnalRepository(_session);
            coaRepository = new CoaRepository(_session);
        }

        #region IJurnalServices Members

        public List<JurnalDTO> GetList(int page, out long recordCount, string sortProperty = null,
                                             string sortType = "ASC")
        {
            var Jurnals = new List<Jurnal>();
            var Results = new List<JurnalDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                Jurnals = jurnalRepository.GetDataPaged(page, 30, "NoVoucher","ASC").ToList();
            }
            else
            {
                Jurnals = jurnalRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }
            recordCount = jurnalRepository.RecordCount;

            Results = (from s in Jurnals
                       where s.TipeJurnal == "Umum" || s.TipeJurnal == "Penyesuaian"
                       select new JurnalDTO
                                  {
                                     NoVoucher = s.NoVoucher,
                                     TglJurnal = s.TglJurnal,
                                     Description = s.Description ,
                                     Departemen = s.Departemen
                                  }).ToList();

            return Results;
        }


        public List<JurnalDTO> GetListAll(int page, out long recordCount, string sortProperty = null,
                                            string sortType = "ASC")
        {
            var Jurnals = new List<Jurnal>();
            var Results = new List<JurnalDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                Jurnals = jurnalRepository.GetDataPaged(page, 30, "NoVoucher", "ASC").ToList();
            }
            else
            {
                Jurnals = jurnalRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }
            recordCount = jurnalRepository.RecordCount;

            Results = (from s in Jurnals
                       select new JurnalDTO
                       {
                           NoVoucher = s.NoVoucher,
                           TglJurnal = s.TglJurnal,
                           Description = s.Description,
                           Departemen = s.Departemen
                       }).ToList();

            return Results;
        }

        public bool Save(JurnalDTO JurnalDTO)
        {
            bool res = false;
            try
            {
                jurnalRepository.ExecuteTransactionNative(() =>
                {
                    Jurnal Jurnal = jurnalRepository.GetDataOne(x => x.NoVoucher == JurnalDTO.NoVoucher);

                    if (Jurnal == null)
                    {
                        Jurnal = new Jurnal();
                        Jurnal.InjectFrom(JurnalDTO);
                        Jurnal.JurnalDetails = new List<JurnalDetail>();
                        foreach (var detail in JurnalDTO.JurnalDetails)
                        {
                            var jd = new JurnalDetail();
                            jd.InjectFrom(detail);
                            jd.AccountNumber =
                                detail.Coa.AccountNumber;
                            
                            if (detail.Departemen != null)
                            {
                                jd.Departemen = new Departemen();
                                jd.Departemen.InjectFrom(
                                    detail.Departemen);
                            }
                            Jurnal.JurnalDetails.Add(jd);
                        }

                        //Untuk New entry dari transaksi bukan dari email
                        if (String.IsNullOrEmpty(Jurnal.NoVoucher))
                            Jurnal.NoVoucher = GetLastJurnalNo(JurnalDTO);

                        foreach (var jurnalDetail in Jurnal.JurnalDetails)
                            jurnalDetail.Jurnal = Jurnal;

                        jurnalRepository.SaveOrUpdate(Jurnal);

                        foreach (var source in JurnalDTO.JurnalDetails.Where(x=>x.SalesInvoice != null))
                        {
                            //Kartu Piutang
                            var mutasiPiutangRepo = new MutasiPiutangRepository(_session);
                            var lastmutasiHutang = mutasiPiutangRepo.FindLastMutasi(source.SalesInvoice.Customer.CustomerId, source.SalesInvoice.SINo,
                                                                              Jurnal.TglJurnal);
                            var mutasiPiutang = new MutasiPiutang();
                            mutasiPiutang.SaldoAwal = lastmutasiHutang.SaldoSisa;
                            mutasiPiutang.SaldoMasuk = source.Debit;
                            mutasiPiutang.SaldoKeluar = source.Kredit;
                            mutasiPiutang.SaldoSisa = mutasiPiutang.SaldoAwal + mutasiPiutang.SaldoMasuk - mutasiPiutang.SaldoKeluar;
                            mutasiPiutang.CustomerId = source.SalesInvoice.Customer.CustomerId;
                            mutasiPiutang.Tanggal = Jurnal.TglJurnal;
                            mutasiPiutang.Type = Jurnal.TipeJurnal;
                            mutasiPiutang.InvoiceNo = source.SalesInvoice.SINo;
                            mutasiPiutang.Coa = source.Coa.AccountNumber;
                            mutasiPiutang.ReferenceNumber = Jurnal.NoVoucher;
                            mutasiPiutangRepo.SaveOrUpdate(mutasiPiutang);
                        }

                        foreach (var source in JurnalDTO.JurnalDetails.Where(x => x.PurchaseInvoice != null))
                        {
                            //Kartu Hutang
                            var mutasiHutangRepo = new MutasiHutangRepository(_session);
                            var lastmutasiHutang = mutasiHutangRepo.FindLastMutasi(source.PurchaseInvoice.Supplier.SupplierId, source.PurchaseInvoice.PINo,
                                                                              Jurnal.TglJurnal);
                            var mutasiHutang = new MutasiHutang();
                            mutasiHutang.SaldoAwal = lastmutasiHutang.SaldoSisa;
                            mutasiHutang.SaldoMasuk = source.Kredit;
                            mutasiHutang.SaldoKeluar = source.Debit;
                            mutasiHutang.SaldoSisa = mutasiHutang.SaldoAwal + mutasiHutang.SaldoMasuk - mutasiHutang.SaldoKeluar;
                            mutasiHutang.SupplierId = source.PurchaseInvoice.Supplier.SupplierId;
                            mutasiHutang.Tanggal = Jurnal.TglJurnal;
                            mutasiHutang.Type = Jurnal.TipeJurnal;
                            mutasiHutang.InvoiceNo = source.PurchaseInvoice.PINo;
                            mutasiHutang.Coa = source.Coa.AccountNumber;
                            mutasiHutang.ReferenceNumber = Jurnal.NoVoucher;
                            mutasiHutangRepo.SaveOrUpdate(mutasiHutang);
                        }
                    }
                    else
                    {
                        //Jika Status Void dan Close tdk boleh Update
                        jurnalRepository.Delete(Jurnal);
                        var jurnal = new Jurnal();
                        jurnal.modified_date = DateTime.Now;
                        jurnal.created_date = Jurnal.created_date;

                        jurnal.InjectFrom(JurnalDTO);
                        jurnal.JurnalDetails = new List<JurnalDetail>();
                        foreach (var detail in JurnalDTO.JurnalDetails)
                        {
                            var jd = new JurnalDetail();
                            jd.InjectFrom(detail);
                            jd.AccountNumber =
                                detail.Coa.AccountNumber;

                            if (detail.Departemen != null)
                            {
                                jd.Departemen = new Departemen();
                                jd.Departemen.InjectFrom(
                                    detail.Departemen);
                            }
                            jurnal.JurnalDetails.Add(jd);
                        }

                        foreach (var siDetail in jurnal.JurnalDetails)
                            siDetail.Jurnal = jurnal;
                        jurnalRepository.Session.SaveOrUpdateCopy(jurnal);

                        var mutasiPiutangRepo = new MutasiPiutangRepository(_session);
                        mutasiPiutangRepo.DeleteMutasiPiutang(Jurnal.NoVoucher);
                        foreach (var source in JurnalDTO.JurnalDetails.Where(x => x.SalesInvoice != null))
                        {
                            //Kartu Piutang
                            var lastmutasiHutang = mutasiPiutangRepo.FindLastMutasi(source.SalesInvoice.Customer.CustomerId, source.SalesInvoice.SINo,
                                                                              Jurnal.TglJurnal);
                            var mutasiPiutang = new MutasiPiutang();
                            mutasiPiutang.SaldoAwal = lastmutasiHutang.SaldoSisa;
                            mutasiPiutang.SaldoMasuk = source.Debit;
                            mutasiPiutang.SaldoKeluar = source.Kredit;
                            mutasiPiutang.SaldoSisa = mutasiPiutang.SaldoAwal + mutasiPiutang.SaldoMasuk - mutasiPiutang.SaldoKeluar;
                            mutasiPiutang.CustomerId = source.SalesInvoice.Customer.CustomerId;
                            mutasiPiutang.Tanggal = Jurnal.TglJurnal;
                            mutasiPiutang.Type = Jurnal.TipeJurnal;
                            mutasiPiutang.InvoiceNo = source.SalesInvoice.SINo;
                            mutasiPiutang.Coa = source.Coa.AccountNumber;
                            mutasiPiutang.ReferenceNumber = Jurnal.NoVoucher;
                            mutasiPiutangRepo.SaveOrUpdate(mutasiPiutang);
                        }


                        var mutasiHutangRepo = new MutasiHutangRepository(_session);
                        mutasiHutangRepo.DeleteMutasiHutang(Jurnal.NoVoucher);
                        foreach (var source in JurnalDTO.JurnalDetails.Where(x => x.PurchaseInvoice != null))
                        {
                            //Kartu Hutang
                            var lastmutasiHutang = mutasiHutangRepo.FindLastMutasi(source.PurchaseInvoice.Supplier.SupplierId, source.PurchaseInvoice.PINo,
                                                                              Jurnal.TglJurnal);
                            var mutasiHutang = new MutasiHutang();
                            mutasiHutang.SaldoAwal = lastmutasiHutang.SaldoSisa;
                            mutasiHutang.SaldoMasuk = source.Kredit;
                            mutasiHutang.SaldoKeluar = source.Debit;
                            mutasiHutang.SaldoSisa = mutasiHutang.SaldoAwal + mutasiHutang.SaldoMasuk - mutasiHutang.SaldoKeluar;
                            mutasiHutang.SupplierId = source.PurchaseInvoice.Supplier.SupplierId;
                            mutasiHutang.Tanggal = Jurnal.TglJurnal;
                            mutasiHutang.Type = Jurnal.TipeJurnal;
                            mutasiHutang.InvoiceNo = source.PurchaseInvoice.PINo;
                            mutasiHutang.Coa = source.Coa.AccountNumber;
                            mutasiHutang.ReferenceNumber = Jurnal.NoVoucher;
                            mutasiHutangRepo.SaveOrUpdate(mutasiHutang);
                        }

                    }


                    res = true;
                });


            }
            catch (Exception)
            {
                res = false;
                throw;
            }

            return res;
        }


        public bool Delete(JurnalDTO jurnalDto)
        {
            bool res;
            try
            {
                Jurnal Jurnal = jurnalRepository.GetDataOne(x => x.NoVoucher == jurnalDto.NoVoucher);
                jurnalRepository.ExecuteTransactionNative(() =>
                                                                    {
                                                                        jurnalRepository.Delete(Jurnal);
                                                                    });
                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public List<JurnalDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression, int page,
                                                       out long recordCount)
        {
            var Jurnals = new List<Jurnal>();
            var Results = new List<JurnalDTO>();
            Jurnals = jurnalRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = jurnalRepository.RecordCount;
            Results = (from s in Jurnals
                       where s.TipeJurnal == "Umum" || s.TipeJurnal == "Penyesuaian"
                       select new JurnalDTO
                       {
                           NoVoucher = s.NoVoucher,
                           TglJurnal = s.TglJurnal,
                           Description = s.Description,
                           Departemen = s.Departemen
                       }).ToList();

            return Results;
        }

        public JurnalDTO GetJurnal(string noVoucher)
        {
            Jurnal Jurnal = jurnalRepository.GetDataOne(x => x.NoVoucher == noVoucher);
            var JurnalDto = new JurnalDTO();
            JurnalDto.InjectFrom(Jurnal);
            JurnalDto.JurnalDetails = new ObservableCollection<JurnalDetailDTO>();
            foreach (var jurnalDetail in Jurnal.JurnalDetails)
            {
                var jd = new JurnalDetailDTO();
                jd.InjectFrom(jurnalDetail);

                if (jurnalDetail.Departemen != null)
                {
                    jd.Departemen = new DepartemenDTO();
                    jd.Departemen.InjectFrom(jurnalDetail.Departemen);

                }
                jd.Coa = new CoaDTO();
                var coa = coaRepository.GetDataOne(x => x.AccountNumber == jurnalDetail.AccountNumber);
                jd.Coa.AccountNumber = jurnalDetail.AccountNumber;
                jd.Coa.AccountName = coa.AccountName;
                JurnalDto.JurnalDetails.Add(jd);
            }

            return JurnalDto;
        }

        public string GetLastJurnalNo(JurnalDTO jurnal)
        {
            var appParamServices = new AppParamServices();
            AppParamDTO param;
            if (jurnal.TipeJurnal == "Umum")
            {
                param = appParamServices.GetAppParamList("KodeJU").FirstOrDefault();
            }else
            {
                param = appParamServices.GetAppParamList("KodeJP").FirstOrDefault();
            }
            
            if (param == null) throw new Exception("Parameter Kode Jurnal belum diset!");
            string res = jurnalRepository.GetMaxNumber(param.AppParamValue);

            if (string.IsNullOrEmpty(res))
                res = param.AppParamValue;

            string formatSO = "0000";
            string lastNo = string.Empty;
            string kodeSO;
            if (res.Length <= 4)
            {
                lastNo = formatSO;
                kodeSO = res;
            }
            else
            {
                lastNo = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[2];
                kodeSO = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0];
            }
            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(lastNo) + 1).ToString().Length) +
                           (int.Parse(lastNo) + 1);

            return kodeSO + "/" + DateTime.Now.Year + "/" + soNum;
        }

        public bool DeleteDetail(JurnalDetailDTO JurnalDetailDto)
        {
            bool res;
            try
            {
                var SIDetail =
                    jurnalRepository.Session.Get<JurnalDetail>(JurnalDetailDto.JurnalDetailId);
                jurnalRepository.DeleteDetail(SIDetail, JurnalDetailDto.JurnalDetailId);
                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public List<JurnalDTO> GetListByPeriodeAndAkun(DateTime endDate,CoaDTO coa)
        {
            var Jurnals = new List<Jurnal>();
            var Results = new List<JurnalDTO>();
            var startDate = new DateTime(endDate.Year, endDate.Month, 1);
            Jurnals = jurnalRepository.GetListByPeriodeAkun(startDate, endDate, coa.AccountNumber).ToList();

            foreach (var jurnal in Jurnals)
            {
                JurnalDTO JurnalDto = new JurnalDTO();
                JurnalDto.InjectFrom(jurnal);
                JurnalDto.JurnalDetails = new ObservableCollection<JurnalDetailDTO>();
                foreach (var jurnalDetail in jurnal.JurnalDetails)
                {
                    if (jurnalDetail.AccountNumber == coa.AccountNumber)
                    {
                        var jd = new JurnalDetailDTO();
                        jd.InjectFrom(jurnalDetail);
                        if (jurnalDetail.Departemen != null)
                        {
                            jd.Departemen = new DepartemenDTO();
                            jd.Departemen.InjectFrom(jurnalDetail.Departemen);
                        }
                        jd.Coa = coa;
                        JurnalDto.JurnalDetails.Add(jd);

                    }
              }

                Results.Add(JurnalDto);
            }
            

            return Results;
        }

        #endregion
    }
}